#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <string.h>
#include <list>
#include <map>
#include <sys/ioctl.h>
#include <net/if.h>
#include "definitions.hpp"

using namespace std;

// Global Variables Begin //

list<string> interface_list;
map<string,string> ipadd_map;

list<unsigned char*> packet_q_i1;
list<unsigned char*> packet_q_i2;
list<unsigned char*> packet_q_i3;
list<unsigned char*> packet_q_i4;



// Global Variables End //


// Parse ARP Begin //

void parse_arp(){
	char buffer[4000];
	FILE *fp = fopen("/proc/net/arp","r");
	if(fp == NULL){
		cerr<<"Error in opening file! Please try again\n";
		//exit(1);
	}
        bzero(buffer,4000);
	int loop_counter = 0;
	while(fgets(buffer,4000,fp)!=NULL){
	loop_counter++;
		if(loop_counter == 1){
			continue;
		}else{
			//Parse buffer here
			int inner_loop = 0;
			char *pch;
			pch = strtok (buffer," ");
			string ipadd;
  			while (pch != NULL)
  			{
				inner_loop++;

				if(inner_loop == 1) // Parse for IPAddress, making the last 8 Bits zero
				{	ipadd.clear();
					ipadd = string(pch);
					//ipadd[ipadd.length()-1] = '0';
				}

				if(inner_loop == 4)
				{
					string macadd = string(pch);
					pch = strtok (NULL," ");
					pch = strtok (NULL," ");

					string inter = string(pch);
					inter = inter.substr(0,inter.length()-1);

					string ipadd_tmp;
					ipadd_tmp.clear();
					ipadd_tmp = ipadd.substr(0,4);
					if(ipadd_tmp.compare("10.1") == 0){
					//push to interface list
					interface_list.push_back(inter);
					//push to ip address map
					ipadd_map[inter] = macadd;
					}
				}
			       pch = strtok (NULL, " ");
 		    }
		}

	bzero(buffer,4000);

	}

}

// Parse ARP End //

int main(){

  // Populate Tables on Memory Begin//
  parse_arp();
  // Populate Tables on Memory End//

   int rc;
   long t;
   void *status;

  int num_thread = ipadd_map.size();
  cout<<"num thread ois "<<num_thread<<endl;
  long *taskids[num_thread];
  pthread_t threads[num_thread];
  pthread_t thread_sniff[num_thread];

  for(t=0; t<num_thread; t++)
  {
    taskids[t] = (long *) malloc(sizeof(long));
    *taskids[t] = (t+1);
    pthread_attr_t attr_sniffer1;
    int thrd_sniffer1=0;
    pthread_attr_init(&attr_sniffer1);
    pthread_attr_setdetachstate(&attr_sniffer1, PTHREAD_CREATE_JOINABLE);
    thrd_sniffer1=pthread_create(&threads[t],&attr_sniffer1,sniffer_thread_func,(void *)taskids[t]);
    if(thrd_sniffer1){
      cerr<<"Error; return code from thread sniffer1 create call is"<<thrd_sniffer1<<endl;
      exit(-1);
    }
    pthread_attr_destroy(&attr_sniffer1);

   // Sniffer1 Thread End          //

            pthread_attr_t attr_rdwrif1;
            int thrd_rdwrif1=0;
            pthread_attr_init(&attr_rdwrif1);
            pthread_attr_setdetachstate(&attr_rdwrif1, PTHREAD_CREATE_JOINABLE);

            thrd_rdwrif1=pthread_create(&thread_sniff[t],&attr_rdwrif1,rdwrif_thread_func,(void *)taskids[t]);
            if(thrd_rdwrif1){
                cerr<<"Error; return code from thread rdwrif1 create call is"<<thrd_rdwrif1<<endl;
                exit(-1);
            }

  pthread_attr_destroy(&attr_rdwrif1);
    
  }

  for(t=0; t<num_thread; t++) {
      rc = pthread_join(threads[t], &status);
      if (rc) {
         printf("ERROR; return code from pthread_join() is %d\n", rc);
         exit(-1);
         }
      printf("Main: completed join with thread %ld having a status of %ld\n",t,(long)status);
      }

 for(t=0; t<num_thread; t++) {
      rc = pthread_join(thread_sniff[t], &status);
      if (rc) {
         printf("ERROR; return code from pthread_join() is %d\n", rc);
         exit(-1);
         }
      printf("Main: completed join with thread %ld having a status of %ld\n",t,(long)status);
      }

  return 1;
}
